#include "util/log.h"

#include <cassert>
#include <stdio.h>
#include <string.h>

#ifdef _PLATFORM_WII
	#include <revolution.h>
#endif//_PLATFORM_WII
#ifdef _PLATFORM_WIN32
	#include <windows.h>
#elif WIN32
	#include <windows.h>		

#endif//_PLATFORM_WII

#ifdef _PLATFORM_ANDROID
#include <android/log.h>
#endif

#include "file_io.h"
#include "common_macros.h"
#include "util/mmgr.h"

using namespace util;

Logger&	Logger::Instance()
{
	static Logger Inst;
	return Inst;
}

Logger::Logger() : 
	m_Verbose(true),
	m_AutoFlush(true),
	m_CurrentType(MSG_INVALID),
	m_MaxSize(4096),
	m_CurrentSize(0),
	m_pConFunc(NULL),
	m_pFile(0),
	m_OutputStdOut(false)
{
	for (int i=0; i<MSG_TYPEC; i++)
		m_MessageMap[i] = LOG_FILE | LOG_CONSOLE | LOG_DEBUGWINDOW;
	m_MessageMap[MSG_FATAL] = LOG_FILE | LOG_CONSOLE | LOG_DEBUGWINDOW;
	m_pData = new char[m_MaxSize];

#ifdef __APPLE__
	m_OutputStdOut = true;
#endif

}

Logger::~Logger()
{
	Shutdown();
}


void			Logger::Shutdown()
{
	FlushData();
	UTIL_SAFE_DELETE(m_pFile);
}

void			Logger::SetBehaviour(MSG_TYPE t, LOG_TYPE l)
{
	if (t < MSG_TYPEC && l <LOG_TYPE_LAST)
		m_MessageMap[t] = l;
}

void			Logger::Init(const std::string& LogName, bool Append)
{
	if (m_pFile)
	{
		_LOG(MSG_WARNING, "Log already open.. why are you trying to open again?");
		return;
	}
	m_pFile = new FileIO();

// ios is not allow to save temp files.
#ifndef _PLATFORM_IOS	
#ifndef _PLATFORM_ANDROID
    if (Append)
	{
		m_pFile->Open(LogName, FileIO::FILE_WRITE | FileIO::FILE_ASCII);
		//m_pFile = fopen(LogName.c_str(), "wa");
	}
	else
	{
		m_pFile->Open(LogName, FileIO::FILE_WRITE | FileIO::FILE_ASCII);
		//m_pFile = fopen(LogName.c_str(), "w");
	}
#endif
#endif
	
	
	m_LogFile = LogName;
	_LOG(MSG_INIT, "--------------------------- SESSION STARTING -------------------------\n");
	// Most compilers don't support __DATE__/__TIME__
	#ifdef _PLATFORM_WIN32
		_LOG(MSG_INIT, " Date : " << __DATE__ << ", Time : " << __TIME__);
	#endif//_PLATFORM_WIN32



}

void			Logger::StartLine(MSG_TYPE Type, const char* Filename, int Line)
{
#ifdef	_LOGGER_MT_	
	m_CS.Enter();
#endif

	m_CurrentType = Type;
	if (m_Verbose &&  Type != MSG_SCRIPT)
	{
		char	Buffer[256];
		sprintf(Buffer, "%s(%i)> ",Filename, Line);
		AddData(Buffer);
	}
}

void			Logger::EndLine()
{
	char	MsgType[50];
	if (m_Verbose)
	{
		switch (m_CurrentType)
		{
			case MSG_FATAL:		strcpy(MsgType, "  [MSG_FATAL]\n"); break;
			case MSG_ERROR:		strcpy(MsgType, "  [MSG_ERROR]\n"); break;
			case MSG_WARNING:	strcpy(MsgType, "  [MSG_WARNING]\n"); break;
			case MSG_INIT:		strcpy(MsgType, "  [MSG_INIT]\n"); break;
			case MSG_LOAD:		strcpy(MsgType, "  [MSG_LOAD]\n"); break;
			case MSG_COMMENT:	strcpy(MsgType, "  [MSG_COMMENT]\n"); break;
			case MSG_SCRIPT:	strcpy(MsgType, "  [MSG_SCRIPT]\n"); break;
			default:
				strcpy(MsgType, "  [MSG_UNKNOWN]\n"); break;
		}
	} else
	{
		strcpy(MsgType, " \n"); 
	}

	AddData(MsgType);

	if (m_AutoFlush)		FlushData();


	m_CurrentType = MSG_INVALID;
#ifdef	_LOGGER_MT_	
	m_CS.Leave();
#endif

}

void			Logger::FlushData()
{
	if (!m_pData) return;

	if (m_MessageMap[m_CurrentType] & LOG_FILE)			FlushToFile();
	if (m_MessageMap[m_CurrentType] & LOG_CONSOLE)		FlushToConsole();
	if (m_MessageMap[m_CurrentType] & LOG_DEBUGWINDOW)	FlushToDebug();
	if (m_MessageMap[m_CurrentType] & LOG_NETWORK)		FlushToNetwork();

	// clear data
	memset(m_pData, 0, m_MaxSize);
	m_CurrentSize = 0;
}

void		Logger::FlushToFile()
{
	if(m_pData && m_pFile)
	{
		m_pFile->WriteStr(m_pData);
	}
}

void		Logger::FlushToConsole()
{
	if (m_pConFunc && m_pData)
		m_pConFunc(m_pData);
}

void		Logger::FlushToDebug()
{
	// do nothing for now
	if (m_pData)
	{
#ifdef _PLATFORM_WII
//#if __ide_target("Debug")
		OSReport(m_pData);	// there's no output from the Wii in release mode anyways.
//#endif
#endif

#ifdef WIN32
		OutputDebugString( m_pData );
#endif

		const char* Temp = m_pData;

#ifdef _PLATFORM_ANDROID
//#ifndef NDEBUG
		const char* test = "fuck";
	__android_log_print(ANDROID_LOG_INFO, "log:", m_pData ,"");
//#endif
#endif

		if (m_OutputStdOut)
		{
			printf(m_pData, "");
		}
	}
}

void		Logger::FlushToNetwork()
{
	// do nothing for now	
}

void			Logger::AddData(const char*	Str)
{
	unsigned int	StrSize = strlen(Str) + 1;
	if (StrSize > m_MaxSize) return;	// no logging, too big.
//	assert(StrSize < m_MaxSize && "Invalid Max Size; there's a string larger than it!");
	if (m_CurrentSize + StrSize >= m_MaxSize)
		FlushData();
	
	if (m_CurrentSize > 0) m_CurrentSize--;	// drop the trailing \0
	memcpy(&m_pData[m_CurrentSize], Str, StrSize);
	m_CurrentSize+=StrSize;
}

Logger&	Logger::operator << (const std::string& d)
{
	AddData(d.c_str());
	return *this;
}

Logger&	Logger::operator << (int		d)
{
	char	Buffer[50];
	sprintf(Buffer, "%i", d);
	AddData(Buffer);
	return *this;
}

Logger&	Logger::operator << (long	d)
{
	char	Buffer[50];
	sprintf(Buffer, "%i", d);
	AddData(Buffer);
	return *this;
}

Logger&	Logger::operator << (unsigned int		d)
{
	char	Buffer[50];
	sprintf(Buffer, "%i", d);
	AddData(Buffer);
	return *this;
}

Logger&	Logger::operator << (unsigned long		d)
{
	char	Buffer[50];
	sprintf(Buffer, "%i", d);
	AddData(Buffer);
	return *this;
}


Logger&	Logger::operator << (double				d)
{
	char	Buffer[50];
	sprintf(Buffer, "%f", d);
	AddData(Buffer);
	return *this;
}

Logger&	Logger::operator << (signed long long		d)
{
	char	Buffer[50];
	sprintf(Buffer, "%I64d", d);
	AddData(Buffer);
	return *this;
}
Logger&	Logger::operator << (unsigned long long		d)
{
	char	Buffer[50];
	sprintf(Buffer, "%I64u", d);
	AddData(Buffer);
	return *this;
}
